# 编写一个简单的装饰器，在函数执行前后打印“开始执行”和“结束执行”
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("开始执行")
        result = func(*args, **kwargs)
        print("结束执行")
        return result
    return wrapper

@my_decorator
def say_hello():
    print("hello world")

say_hello()

print("=" * 50)
# 编写一个装饰器，可以接受一个字符串参数，并在调用被装饰函数时打印这个字符串
def my_decorator2(message):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print("装饰器上的参数:", message)
            result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@my_decorator2("这是一个装饰器")
def say_hello2(name, age):
    print(f"hello {name}, your age is {age}")

say_hello2("张三",18)

print("=" * 50)
# 编写一个装饰器，用它来装饰类，并在实例化类时打印“创建一个新的实例”
def my_decorator3(cls):
    class WrapperClass:
        def __init__(self, *args, **kwargs):
            print("创建一个新的实例")
            self.obj = cls(*args, **kwargs)
        def __getattr__(self, name):
            return getattr(self.obj, name)
        def __setattr__(self, name, value):
            if name == "obj":
                self.__dict__[name] = value
            else:
                setattr(self.obj, name, value)
    return WrapperClass

@my_decorator3
class MyClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def say_hello(self):
        print(f"hello {self.name}, your age is {self.age}")

my_class = MyClass("张三",18)
my_class.say_hello()

print("=" * 50)
# 一个函数上使用多个装饰器
# 下面两个装饰器执行的顺序是：my_decorator2 -> my_decorator
@my_decorator
@my_decorator2("这是一个装饰器")
def say_hello3(name, age):
    print(f"hello {name}, your age is {age}")

say_hello3("张三",18)

print("=" * 50)
from functools import wraps
# 使用装饰器来实现一个缓存函数返回值的功能
def cache_result(func):
    cache = {}
    @wraps(func)
    def wrapper(*args, **kwargs):
        key = args + tuple(kwargs.items())
        if key in cache:
            return cache[key]
        result = func(*args, **kwargs)
        cache[key] = result
        return result
    return wrapper

@cache_result
def add(a, b):
    return a + b
print(add(1, 2))
print(add(1, 2))
